package com.jy.modules.cims.common.sysUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.jy.modules.cims.common.exception.CimsException;
import com.jy.modules.cims.common.exception.CimsExceptionConstant;

@Component
public class BatchInvokeUtils {
	private static final Logger logger = LoggerFactory.getLogger(BatchInvokeUtils.class);
	private static final int MAX_BATCH_COUNT = 999;// 每一次执行的最大条数
	private static final String KEY_LAST_BATCH = "lastBatch";// 是否最后一批次的MAP的KEY标识
	private static final String LAST_BATCH_NO = "0";// 是否最后一批次的值(0:不是; 1:是)
	private static final String LAST_BATCH_YES = "1";// 是否最后一批次的值(0:不是; 1:是)

	@Autowired
	private SpringContextUtils springContextUtils;

	/**
	 * @Description 批量调用
	 * @param executeClass
	 *            执行类
	 * @param executeMethod
	 *            执行方法名,该执行类方法要在类中定义公用<code>public</code>的方法。<br>
	 * @param paramterList
	 *            参数List，要分批处理的参数集合。
	 * @param paramterMap
	 *            参数Map，可以将返回结果放入此参数传递。
	 * @param batchCount
	 *            每一次执行的条数。
	 * @return 多次执行接口返回结果的数组。如果接口没有返回值，返回将是空；如果接口有返回非空值，返回有值，需要此值需要值做转换。
	 * @author shengzhoutao
	 * @date 2015-5-26
	 */
	public <T> Object[] batchInvoke(Class<?> executeClass, String executeMethod, List<T> paramterList, Map<Object, Object> paramterMap, int batchCount) {
		if (null == executeClass || (!SimpleStringUtils.hasText(executeMethod)) || null == paramterList) {
			return null;
		}

		if (paramterList.isEmpty()) {
			Object obj = invoke(executeClass, executeMethod, paramterList, paramterMap);
			return new Object[] { obj };
		}

		if (batchCount == 0 || batchCount > MAX_BATCH_COUNT) {
			batchCount = MAX_BATCH_COUNT;
		}

		int listSize = paramterList.size();// 执行总条数

		int maxInvokeCount = listSize / batchCount;// 最大执行次数
		int invokeCount = (listSize % batchCount == 0) ? maxInvokeCount : maxInvokeCount + 1;// 实际要执行次数
		int invokeIndex = 0;// 执行次数，每次执行次数加一

		List<T> dealList = new ArrayList<T>();
		List<Object> result = new ArrayList<Object>();
		for (int index = 0; index < listSize; index++) {
			T t = paramterList.get(index);
			dealList.add(t);
			if ((index + 1) % batchCount == 0 || (index + 1) == listSize) {

				// --------------------------------------------------
				// 存放是否最后一批次的值
				invokeIndex += 1;// 每次执行次数加一
				if (null != paramterMap) {
					if (invokeIndex == invokeCount) {
						paramterMap.put(KEY_LAST_BATCH, LAST_BATCH_YES);
					} else {
						paramterMap.put(KEY_LAST_BATCH, LAST_BATCH_NO);
					}
				}
				// --------------------------------------------------

				// 执行处理
				Object obj = invoke(executeClass, executeMethod, dealList, paramterMap);
				result.add(obj);
				dealList.clear();
			}
		}
		dealList = null;
		return result.toArray();
	}

	/**
	 * @Description 执行处理
	 * @param executeClass
	 *            执行类
	 * @param executeMethod
	 *            执行方法名,该执行类方法要在类中定义公用<code>public</code>的方法。<br>
	 * @param paramterList
	 *            参数List，要批处理的参数集合。
	 * @param paramterMap
	 *            参数Map，可以将返回结果放入此参数传递。
	 * @return 执行接口返回结果。如果接口没有返回值，返回将是空；如果接口有返回非空值，返回有值，需要此值需要值做转换。
	 * @author shengzhoutao
	 * @date 2015-5-26
	 */
	private <T> Object invoke(final Class<?> executeClass, final String executeMethod, final List<T> argsList, Map<Object, Object> argsMap) {
		Object result = null;
		try {
			Object bean = springContextUtils.getBean(executeClass.getName());
			if (null == bean) {
				throw new CimsException(MessageFormat.format(CimsExceptionConstant.NOT_INTO_BEAN, new Object[] { executeClass.getName() }));
			}

			Class<?>[] parameterTypes = null;
			Method method = null;
			if (null != argsMap) {
				parameterTypes = new Class[] { java.util.List.class, java.util.Map.class };
				method = executeClass.getMethod(executeMethod, parameterTypes);
				if (null == method) {
					throw new CimsException("根据类名,方法名,参数未获取到执行的方法，请检查执行接口传入的信息是否正确.");
				}
				// 通过反射获取要调用的方法
				result = method.invoke(bean, argsList, argsMap);
			} else {
				parameterTypes = new Class[] { java.util.List.class };
				method = executeClass.getMethod(executeMethod, parameterTypes);
				if (null == method) {
					throw new CimsException("根据类名,方法名,参数未获取到执行的方法，请检查执行接口传入的信息是否正确.");
				}
				// 通过反射获取要调用的方法
				result = method.invoke(bean, argsList);
			}
		} catch (InvocationTargetException e) {
		    Throwable throwable = e.getTargetException();// 获取目标异常  
			throw new CimsException(throwable.getMessage());
		} catch (Exception e) {
			logger.error("分批处理异常：", ExceptionUtils.getStackTraceAsString(e));
			throw new CimsException("分批处理异常：", e);
		}

		return result;
	}

}
